package org.naive.vstream.render;

import java.io.IOException;
import java.io.InputStream;
import java.util.Deque;
import java.util.LinkedList;

public abstract class AbstractRenderer {
	private final int width;

	private final int height;

	private RendererState nextState;

	private boolean isCurrentStateDone;

	private final QuadTreeStack stack = new QuadTreeStack();

	private final Deque<RendererState> states = new LinkedList<RendererState>();

	public AbstractRenderer(int w, int h) {
		width = w;
		height = h;

		stack.push();
		states.push(new RendererState(0, 0, w, h));
		setActive(states.peek(), null);
	}

	public QuadTreeStack getQuadStack() {
		return stack;
	}

	public void loop(InputStream input) throws IOException {
		int bte = input.read();
		while (bte != -1) {
			handleByte(bte);
			bte = input.read();
		}
	}

	protected abstract void outPixel(int x, int y, int brightness);

	protected void outRect(int x, int y, int w, int h, int brightness) {
		for (int yy = y; yy < h + y; ++yy) {
			for (int xx = x; xx < x + w; ++xx) {
				outPixel(xx, yy, brightness);
			}
		}
	}

	private void handleByte(int data) {
		int mask = 0x1;
		for (int i = 0; i <= 7; i++) {
			handleBit((data & mask) != 0);
//			try {
//				Thread.sleep(3);
//			}
//			catch (InterruptedException e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}
			mask <<= 1;
		}
	}

	private void handleBit(boolean bit) {
		states.peek().handleBit(bit);

		if (nextState != null) {

			final RendererState top = states.peek();
			setActive(nextState, top);
			states.push(nextState);
			nextState = null;
		}
		if (isCurrentStateDone) {
			final RendererState last = states.pop();

			setActive(states.peek(), last);

			isCurrentStateDone = false;
		}
	}

	private void setActive(RendererState activated, RendererState deactivated) {
		if (activated != null) {
			activated.activate(this, deactivated);
		}
		if (deactivated != null) {
			deactivated.deactivate(this);
		}
	}

	public void scheduleState(RendererState successor) {
		nextState = successor;
	}

	public void scheduleDone() {
		isCurrentStateDone = true;
	}

}
